#include "ntddk.h"

#define GDT_DRIVER_DEVICE_NAME L"\\Device\\GdtDriver"
#define GDT_DRIVER_SYMLINK_NAME L"\\DosDevices\\GDTD"

#define WORD  unsigned short
#define DWORD unsigned int

#define GDT_SIZE 65536 + sizeof(struct TABLE_INFO)
#define GDT_ENTRY_SIZE 8
                                        
#pragma pack(push, 1)	 
struct TABLE_INFO
{
	WORD  size;
	DWORD base;
};
#pragma pack(pop)

char driverBuffer [GDT_SIZE];

NTSTATUS DriverStub  (IN PDEVICE_OBJECT dev, IN PIRP irp);
NTSTATUS driverControl (IN PDEVICE_OBJECT dev, IN PIRP irp);
VOID     driverUnload  (IN PDRIVER_OBJECT dev);
NTSTATUS write(IN PDEVICE_OBJECT dev, IN PIRP irp);
NTSTATUS read(IN PDEVICE_OBJECT dev, IN PIRP irp);

NTSTATUS complete(int size, IN PIRP irp)
{        
        irp->IoStatus.Status      = STATUS_SUCCESS;
        irp->IoStatus.Information = size;
        IoCompleteRequest(irp, IO_NO_INCREMENT);
                 
        return STATUS_SUCCESS;
}
 
NTSTATUS DriverEntry(IN PDRIVER_OBJECT driverObject,IN PUNICODE_STRING RegistryPath)
{
        NTSTATUS       status;
        PDEVICE_OBJECT dev;
        UNICODE_STRING name;
        UNICODE_STRING link;
  
        driverObject->DriverUnload                         	= driverUnload;
        driverObject->MajorFunction[IRP_MJ_CREATE]         	= DriverStub;
        driverObject->MajorFunction[IRP_MJ_CLOSE]          	= DriverStub;
        driverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] 	= DriverStub;
        driverObject->MajorFunction[IRP_MJ_READ] 			= read;
        driverObject->MajorFunction[IRP_MJ_WRITE] 			= DriverStub;
  
        RtlInitUnicodeString(&name, GDT_DRIVER_DEVICE_NAME);
  
        status = IoCreateDevice(driverObject, sizeof(PDEVICE_OBJECT), &name, FILE_DEVICE_UNKNOWN, 0, FALSE, &dev);
        dev->Flags |= DO_BUFFERED_IO;
        if(!NT_SUCCESS(status))return status;
        RtlInitUnicodeString(&link, GDT_DRIVER_SYMLINK_NAME);
  
        return IoCreateSymbolicLink(&link,&name);
}
  
NTSTATUS DriverStub(IN PDEVICE_OBJECT dev, IN PIRP irp)
{
        return STATUS_SUCCESS;
}
  
VOID driverUnload(IN PDRIVER_OBJECT dev)
{
        UNICODE_STRING deviceLink;
        RtlInitUnicodeString(&deviceLink, GDT_DRIVER_SYMLINK_NAME);
        IoDeleteSymbolicLink(&deviceLink);
        IoDeleteDevice(dev->DeviceObject);
}

void writeTableToBuffer(char* buffer, struct TABLE_INFO* table)
{
	memcpy(buffer, table, sizeof(struct TABLE_INFO));
	memcpy(buffer + sizeof(struct TABLE_INFO), table->base, table->size);
}

NTSTATUS read(IN PDEVICE_OBJECT fdo, IN PIRP irp)
{
	struct TABLE_INFO gdt;
	PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(irp);
	void* buffer = irp->AssociatedIrp.SystemBuffer;
	long size = stack->Parameters.Read.Length;
	
	if (size < GDT_SIZE)  return complete(0, irp);
	
	
	__asm { 
		SGDT gdt;
	}
	
	DbgPrint("addr: %u\tsize: %u\n", gdt.base, gdt.size);
	
	writeTableToBuffer(&driverBuffer, &gdt);

	RtlCopyMemory(buffer, (void*)(&driverBuffer), GDT_SIZE);
	return complete(GDT_SIZE, irp);
}
